/*
 * Copyright (C) 2013 rdrrlabs gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.rdrrlabs.example.timer2app.pub.ui;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.rdrrlabs.example.liblabs.app.Bus;
import com.rdrrlabs.example.liblabs.app.Bus.Register;
import com.rdrrlabs.example.liblabs.app.IBusListener;
import com.rdrrlabs.example.timer2app.R;
import com.rdrrlabs.example.timer2app.core.BusConstants;
import com.rdrrlabs.example.timer2app.core.GAEHelper;
import com.rdrrlabs.example.timer2app.core.GlobalContext;
import com.rdrrlabs.example.timer2app.core.GAEHelper.State;
import com.rdrrlabs.example.timer2app.dummy.DummyContent;

/**
 * A list fragment representing a list of Events. This fragment also supports
 * tablet devices by allowing list items to be given an 'activated' state upon
 * selection. This helps indicate which item is currently being viewed in a
 * {@link EventDetailFragment}.
 * <p>
 * Activities containing this fragment MUST implement the {@link Callbacks}
 * interface.
 */
public class EventListFragment
    extends ListFragment   // FIXME use Timeriffic ListFragment2
    implements IBusListener {

    /**
     * The serialization (saved instance state) Bundle key representing the
     * activated item position. Only used on tablets.
     */
    private static final String STATE_ACTIVATED_POSITION = "activated_position";

    /**
     * The fragment's current callback object, which is notified of list item
     * clicks.
     */
    private Callbacks mCallbacks = sDummyCallbacks;

    /**
     * The current activated item position. Only used on tablets.
     */
    private int mActivatedPosition = ListView.INVALID_POSITION;

    private Button mBtnSignIn;
    private TextView mTextSignName;
    private TextView mTextSignInfo;
    private TextView mLinkSignIn;
    private Register<EventListFragment> mBusReg;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callbacks {
        /**
         * Callback for when an item has been selected.
         */
        public void onItemSelected(String id);
    }

    /**
     * A dummy implementation of the {@link Callbacks} interface that does
     * nothing. Used only when this fragment is not attached to an activity.
     */
    private static Callbacks sDummyCallbacks = new Callbacks() {
        @Override
        public void onItemSelected(String id) {
        }
    };

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public EventListFragment() {
    }

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
        mBusReg = Bus.register(this, GlobalContext.getContext().getBus());

        // TODO: replace with a real list adapter.
        setListAdapter(new ArrayAdapter<DummyContent.DummyItem>(getActivity(),
                        android.R.layout.simple_list_item_1,  //FIXME API 11 simple_list_item_activated_1
                        android.R.id.text1, DummyContent.ITEMS));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mBusReg.deregister();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
        //-- Disabled: do not call super since it creates a view root hierarchy that
        //-- we do not need.
        //-- return super.onCreateView(inflater, container, state);
        View root = inflater.inflate(R.layout.fragment_event_master, null /*root*/, false /*attachToRoot*/);

        // On start, the list view should have the focus, if possible.
        final View listView = root.findViewById(android.R.id.list);
        listView.requestFocus();

        mTextSignName = (TextView) root.findViewById(R.id.textAccountName);
        mTextSignInfo = (TextView) root.findViewById(R.id.textInfo);
        mBtnSignIn = (Button) root.findViewById(R.id.btnSignIn);

        if (mBtnSignIn != null) {
            mBtnSignIn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    SignInDialog.showSignInDialog(getActivity());
                }
            });
        }

        mLinkSignIn = (TextView) root.findViewById(R.id.linkSignIn);
        if (mLinkSignIn != null) {
            // get current text
            CharSequence t = mLinkSignIn.getText();
            // make it a spannable
            SpannableString s = new SpannableString(t);
            // create a clickable span
            ClickableSpan cs = new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    listView.requestFocus();    // TODO change focus only on success
                    SignInDialog.showSignInDialog(getActivity());
                }
            };
            // attach the span to the spannable
            s.setSpan(cs, 0, s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

            mLinkSignIn.setMovementMethod(LinkMovementMethod.getInstance());
            mLinkSignIn.setText(s);
        }

        // Start the GAE check 250ms after startup
        mTextSignName.postDelayed(new Runnable() {
            @Override
            public void run() {
                GAEHelper ah = GlobalContext.getContext().getGAEHelper();
                updateSignInfo(ah);
                ah.onActivityStartedCheck(getActivity());
            }
        }, 250 /*ms*/);

        return root;
    }

    @Override
    public void onViewCreated(View view, Bundle state) {
        super.onViewCreated(view, state);

        // Restore the previously serialized activated item position.
        if (state != null && state.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(state.getInt(STATE_ACTIVATED_POSITION));
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Activities containing this fragment must implement its callbacks.
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException(
                            "Activity must implement fragment's callbacks.");
        }

        mCallbacks = (Callbacks) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        // Reset the active callbacks interface to the dummy implementation.
        mCallbacks = sDummyCallbacks;
    }

    @Override
    public void onListItemClick(ListView listView, View view, int position,
                    long id) {
        super.onListItemClick(listView, view, position, id);

        // Notify the active callbacks interface (the activity, if the
        // fragment is attached to one) that an item has been selected.
        mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            // Serialize and persist the activated item position.
            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
        }
    }

    /**
     * Turns on activate-on-click mode. When this mode is on, list items will be
     * given the 'activated' state when touched.
     */
    public void setActivateOnItemClick(boolean activateOnItemClick) {
        // When setting CHOICE_MODE_SINGLE, ListView will automatically
        // give items the 'activated' state when touched.
        getListView().setChoiceMode(
                        activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
                                        : ListView.CHOICE_MODE_NONE);
    }

    private void setActivatedPosition(int position) {
        if (position == ListView.INVALID_POSITION) {
            getListView().setItemChecked(mActivatedPosition, false);
        } else {
            getListView().setItemChecked(position, true);
        }

        mActivatedPosition = position;
    }

    // ---------------

    @Override
    public void onBusMessage(int what, Object object) {
        final GAEHelper ah = GlobalContext.getContext().getGAEHelper();

        if (what == BusConstants.GAE_ACCOUNT_STATE_CHANGED &&
                object == ah.getCurrentState()) {
            mTextSignName.post(new Runnable() {
                @Override
                public void run() {
                    updateSignInfo(ah);
                }
            });
        }
    }

    private void updateSignInfo(final GAEHelper ah) {
        State state = ah.getCurrentState();

        String name = state.mAccountName;
        if (name != null) {
            mTextSignName.setText(name);
        } else {
            mTextSignName.setText(getString(R.string.intro__not_logged));
        }

        String info = state.mDetail;
        if (info == null) {
            switch(state.mState) {
            case State.NO_ACCOUNT:
                info = "Please <select an account> to sign-in.";
                break;
            case State.INVALID_ACCOUNT:
                info = "Invalid account, please <select another account> to sign-in.";
                break;
            case State.AUTH_TOKEN_FAILED:
            case State.AUTH_COOKIE_FAILED:
                info = "Failed to authenticate. <Try again> or <change account>.";
                break;
            default:
                info = "";
            }
        }
        mTextSignInfo.setText(info);
    }
}
